#include <cassert>
#include <gdkmm/pixbuf.h>
#include "colour.h"
#include "gradient.h"

Colour Gradient::getColour(double mu) {
	assert(this->size() > 1);
	Colour low, high, colour;
	double region = 1 / ((double)this->size() - 1);
	int whole = (int)(mu / region);
	double fraction = (mu - (whole * region)) * (1 / region);
	std::list<Colour>::iterator iter = begin();
	while (whole > 0) {
		++iter;
		--whole;
	}
	low = *iter;
	if (mu != 1) {
		++iter;
		high = *iter;
	} else {
		high = low;
	}
	colour.r = (uint8_t)(((double)low.r * (1.0f - fraction)) + ((double)high.r * fraction));
	colour.g = (uint8_t)(((double)low.g * (1.0f - fraction)) + ((double)high.g * fraction));
	colour.b = (uint8_t)(((double)low.b * (1.0f - fraction)) + ((double)high.b * fraction));
	return colour;
}

Glib::RefPtr<Gdk::Pixbuf> Gradient::createPixbuf(int w, int h) {
	assert(this->size() > 1);
	Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create(Gdk::Colorspace(0), false, 8, w, h);
	guint8* data = pixbuf->get_pixels();
	for (int y = 0; y < h; ++y) {
		for (int x = 0; x < w; ++x) {
			Colour colour = getColour((double)x / (double)w);
			data[(((w * 3) + (w % 4)) * y) + (3 * x) + 0] = colour.r;
			data[(((w * 3) + (w % 4)) * y) + (3 * x) + 1] = colour.g;
			data[(((w * 3) + (w % 4)) * y) + (3 * x) + 2] = colour.b;
		}
	}
	return pixbuf;
}
